package org.dashboard.server.calendar;

import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.extensions.When;
import com.google.gdata.util.ServiceException;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.dashboard.client.widget.calendar.CalendarService;
import org.dashboard.shared.calendar.CalendarEvent;
import org.dashboard.shared.calendar.CalendarInfo;
import org.dashboard.shared.Props;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

/**
 * @author Simon Vogensen, Lakeside
 * @version $Revision$
 */
public class CalendarServiceImpl extends RemoteServiceServlet implements CalendarService {

    private static final String METAFEED_URL_BASE = "http://www.google.com/calendar/feeds/";
    private static final String EVENT_FEED_URL_SUFFIX = "/private/full";

    URL eventFeedUrl;

    public ArrayList<CalendarInfo> getWeek() throws IllegalArgumentException {
        try {
            Calendar start = Calendar.getInstance();
            Calendar end = Calendar.getInstance();
            end.add(Calendar.DAY_OF_YEAR, 7);
            List<CalendarEventEntry> list = callGoogleCalendarService(start.getTime(), end.getTime());

            ArrayList<CalendarInfo> result = new ArrayList<CalendarInfo>();

            Calendar cal = Calendar.getInstance();
            for (int i = 0; i < 7; i++) {
                final int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
                if (dayOfWeek == 1 || dayOfWeek == 7) { // if saturday and sunday
                    cal.add(Calendar.DAY_OF_YEAR, 1);
                    continue;
                }
                List<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>();
                for (CalendarEventEntry calendarEventEntry : list) {
                    if (calendarEventEntry.getStatus().getValue().endsWith("canceled")) {
                        continue;
                    }
                    final List<When> times = calendarEventEntry.getTimes();
                    for (When time : times) {
                        final DateTime startTime = time.getStartTime();
                        final DateTime endTime = time.getEndTime();
                        if (new Date(startTime.getValue()).after(cal.getTime())) {
                            continue;
                        }
                        if (new Date(endTime.getValue()).before(cal.getTime())) {
                            continue;
                        }
                        calendarEventList.add(new CalendarEvent(calendarEventEntry.getTitle().getPlainText()));

//                        System.out.println("cal.getTime() = " + cal.getTime());
//                        System.out.print(calendarEventEntry.getTitle().getPlainText());
//                        System.out.print("  --  startTime = " + new Date(startTime.getValue()));
//                        System.out.println("  --  endTime = " + new Date(endTime.getValue()));
                    }
                }
                CalendarInfo info = new CalendarInfo();
                info.setEvents(calendarEventList);
                info.setDayName(cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, new Locale("da","dk")));
                result.add(info);
                cal.add(Calendar.DAY_OF_YEAR, 1);
            }

            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

    public static void main(String[] args) {
        final ArrayList<CalendarInfo> week = new CalendarServiceImpl().getWeek();

        for (CalendarInfo calendarInfo : week) {
            System.out.println("calendarInfo = " + calendarInfo);
        }
/*

        Calendar cal = Calendar.getInstance();

        for (int i = 0; i < 7; i++) {
            final int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
            if (dayOfWeek != 1 && dayOfWeek != 7) { // saturday and sunday
                System.out.println("" + cal.getTime());
                System.out.println("**************************************************");
                System.out.println("dayOfWeek = " + dayOfWeek);
                Date start = cal.getTime();
                start.setHours(0);
                start.setMinutes(0);
                start.setSeconds(0);
                Date end = cal.getTime();
                end.setHours(23);
                end.setMinutes(59);
                end.setSeconds(59);

                print(new CalendarServiceImpl().callGoogleCalendarService(cal.getTime(), cal.getTime()));
            }
            cal.add(Calendar.DAY_OF_YEAR, 1);
        }

        System.out.println("");
        System.out.println("");
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        end.add(Calendar.DAY_OF_YEAR, 7);
        print(new CalendarServiceImpl().callGoogleCalendarService(start.getTime(), end.getTime()));
*/

    }

    private static void print(List<CalendarEventEntry> entries) {
        System.out.println("**************************************************");
        for (CalendarEventEntry entry : entries) {
            if (entry.getStatus().getValue().endsWith("canceled")) {
                continue;
            }
            System.out.println(entry.getTitle().getPlainText());
            final List<When> whens = entry.getTimes();
            for (When when : whens) {
                System.out.println("when.getStartTime() = " + when.getStartTime().toStringRfc822());
                System.out.println("when.getEndTime() = " + when.getEndTime().toStringRfc822());
            }
            System.out.println();
        }
    }

    private List<CalendarEventEntry> callGoogleCalendarService(Date startDate, Date endDate) {
        com.google.gdata.client.calendar.CalendarService myService = new com.google.gdata.client.calendar.CalendarService("calendarwidget-servicecall");

        String userName = Props.instance().getGoogleUsername();
        String userPassword = Props.instance().getGooglePassword();

        // Create the necessary URL objects.
        try {
            eventFeedUrl = new URL(METAFEED_URL_BASE + Props.instance().getGoogleCalendarUrl() + EVENT_FEED_URL_SUFFIX);
        } catch (MalformedURLException e) {
            // Bad URL
            System.err.println("Uh oh - you've got an invalid URL.");
            e.printStackTrace();
        }

        try {
            myService.setUserCredentials(userName, userPassword);
            return dateRangeQuery(myService, new DateTime(startDate), new DateTime(endDate));

        } catch (IOException e) {
            // Communications error
            System.err.println("There was a problem communicating with the service.");
            e.printStackTrace();
        } catch (ServiceException e) {
            // Server side error
            System.err.println("The server had a problem handling your request.");
            e.printStackTrace();
        }
        return null;
    }

    private List<CalendarEventEntry> dateRangeQuery(com.google.gdata.client.calendar.CalendarService service,
                                                    DateTime startTime, DateTime endTime) throws ServiceException, IOException {

        CalendarQuery myQuery = new CalendarQuery(eventFeedUrl);
        myQuery.setMinimumStartTime(startTime);
        myQuery.setMaximumStartTime(endTime);

        // Send the request and receive the response:
        CalendarEventFeed resultFeed = service.query(myQuery, CalendarEventFeed.class);

        List<CalendarEventEntry> result = new ArrayList<CalendarEventEntry>();
        for (int i = 0; i < resultFeed.getEntries().size(); i++) {
            CalendarEventEntry entry = resultFeed.getEntries().get(i);
            result.add(entry);
        }
        return result;
    }

}
